package com.pactera.asmp.server.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.pactera.asmp.server.common.constants.Constants;
import com.pactera.asmp.server.common.constants.ResultCode;
import com.pactera.asmp.server.common.exception.CustomException;
import com.pactera.asmp.server.common.exception.GenericException;
import com.pactera.asmp.server.common.utils.DateUtil;
import com.pactera.asmp.server.dao.ConstantInfoMapper;
import com.pactera.asmp.server.dao.ProjectModuleMapper;
import com.pactera.asmp.server.dao.ScriptInfoMapper;
import com.pactera.asmp.server.entity.*;
import com.pactera.asmp.server.error.ProjectModuleError;
import com.pactera.asmp.server.pojo.ConstantInfo;
import com.pactera.asmp.server.pojo.ScriptInfo2;
import com.pactera.asmp.server.pojo.User;
import com.pactera.asmp.server.utils.AssertUtil;
import com.pactera.asmp.server.utils.PageDataResult;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class ProjectModuleServcieImpl implements ProjectModuleService {

    @Autowired
    private ProjectModuleMapper projectModuleMapper;

    @Autowired
    private ScriptInfoMapper scriptInfoMapper;

    @Autowired
    private ConstantInfoMapper constantInfoMapper;

    @Autowired
    private IRedisService redisService;

    private final static String REDIS_KEY_ALL_MODULE_COMMON = "ALL_MODULE_COMMON";
    private final static int  REDIS_CACHE_EXPIRE = 60*60*24;  // 24小时

    @Override
    @Transactional
    public ResponseResult<ProjectModuleDTO> insert(ProjectModuleDTO record) {
        AssertUtil.notNull(record,"参数异常");
        AssertUtil.notNull(record.getProjectId(),"模块Id不允许为空");
        AssertUtil.hasText(record.getName(),"模块名称不允许为空");

        User currUser = (User) SecurityUtils.getSubject().getPrincipal();
        if(currUser == null)throw new CustomException(ResultCode.PERMISSION_EXPIRE);

        record.setCreateUserId(currUser.getId());
        record.setUpdateUserId(currUser.getId());

        LocalDateTime now = DateUtil.now();
        record.setTimeCreate(now);
        record.setTimeUpdate(now);
        record.setStatus(1);

        // 模块名称不重复
        ProjectModuleDTO projectModuleDTO = projectModuleMapper.selectByProjectIdAndName(record.getProjectId(), record.getName(), null);
        if(projectModuleDTO != null) throw new GenericException(ProjectModuleError.PROJECT_NAME_EXIST_ERROR);

        record.setId(null);
        projectModuleMapper.insert(record);
        return ResponseResult.defaultSuccess(record);
    }


    @Override
    @Transactional
    public ResponseResult<ProjectModuleDTO> update(ProjectModuleDTO record) {
        AssertUtil.notNull(record,"参数异常");
        AssertUtil.notNull(record.getId(),"唯一Id不允许为空");

        User currUser = (User) SecurityUtils.getSubject().getPrincipal();
        if(currUser == null)throw new CustomException(ResultCode.PERMISSION_EXPIRE);
        Integer userId = currUser.getId();
        record.setUpdateUserId(userId);

        LocalDateTime now = DateUtil.now();
        record.setTimeUpdate(now);

        // 模块名称不重复
        ProjectModuleDTO projectModuleDTO = projectModuleMapper.selectByProjectIdAndName(record.getProjectId(), record.getName(), record.getId());
        if(projectModuleDTO != null) throw new GenericException(ProjectModuleError.PROJECT_NAME_EXIST_ERROR);

        projectModuleMapper.update(record);
        return ResponseResult.defaultSuccess(record);
    }

    @Override
    public ResponseResult<PageDataResult> select(ProjectModuleSearch search) {
        AssertUtil.notNull(search,"参数异常");

        PageDataResult pageDataResult = new PageDataResult();

        if (null == search.getPageNum() || search.getPageNum().intValue() == 0) {
            search.setPageNum(1);
        }
        if (null == search.getPageSize() || search.getPageSize().intValue() == 0) {
            search.setPageSize(10);
        }

        if(search.getPageNum().intValue() < 0 || search.getPageSize().intValue() < 0) {
            pageDataResult.setTotals(0);
            pageDataResult.setList(Lists.newArrayList());
            return ResponseResult.defaultSuccess(pageDataResult);
        }
        PageHelper.startPage(search.getPageNum(), search.getPageSize());
        List<ProjectModuleDTO> list = projectModuleMapper.select(search);

        PageInfo<ProjectModuleDTO> pageInfo = new PageInfo<>(list);
        pageDataResult.setTotals((int) pageInfo.getTotal());
        pageDataResult.setList(list);

        return ResponseResult.defaultSuccess(pageDataResult);
    }

    @Override
    public ResponseResult<List<ProjectModuleDTO>> selectAvailableByProjectId(Integer projectId) {
        AssertUtil.notNull(projectId,"项目Id不允许为空");

        ProjectModuleSearch search = new ProjectModuleSearch();
        search.setProjectId(projectId);
        search.setStatus(1);
        List<ProjectModuleDTO> list = projectModuleMapper.select(search);
        return ResponseResult.defaultSuccess(list);
    }

    @Override
    @Transactional
    public ResponseResult batch(ProjectModuleBatchDTO batch) {
        AssertUtil.notNull(batch,"参数异常");
        AssertUtil.notNull(batch.getProjectId(),"项目ID不允许为空");

        User currUser = (User) SecurityUtils.getSubject().getPrincipal();
        if(currUser == null)throw new CustomException(ResultCode.PERMISSION_EXPIRE);

        Integer userId = currUser.getId();
        LocalDateTime now = LocalDateTime.now();

        ProjectModuleDTO existDto;
        int count = 0;

        
        // 1. 先删除，再修改，最后新增  防止名称重复
        // 1 删除
        if(!CollectionUtils.isEmpty(batch.getDelete())) {
            // 判断是否关联脚本
            List<ScriptInfo2> scriptInfo2List = scriptInfoMapper.getScriptByProjecModuletIds(batch.getDelete());
            if(!CollectionUtils.isEmpty(scriptInfo2List)) {
                throw new CustomException(ResultCode.BUSINESS_PROJECT_MODULE_SCRIPT_RELATED);
            }
            // 判断是否关联常量
            List<ConstantInfo> constantInfoList = constantInfoMapper.selectByProjectModuleIds(batch.getDelete());
            if(!CollectionUtils.isEmpty(constantInfoList)) {
                throw new CustomException(ResultCode.BUSINESS_PROJECT_MODULE_CONSTANT_RELATED);
            }
            count += this.projectModuleMapper.delete(batch.getDelete(),userId,now);
        }


        ProjectModuleDTO dto = new ProjectModuleDTO();
        if(!CollectionUtils.isEmpty(batch.getUpdate())){
            // 判断输入项目名称是否重复
            Set<String> names = batch.getUpdate().stream().map(ProjectModuleDTO2::getName).collect(Collectors.toSet());
            if(names.size() != batch.getUpdate().size()) {
                throw new CustomException(ResultCode.PARAM_DUPLICATION);
            }
            for (ProjectModuleDTO2 item : batch.getUpdate()){
                AssertUtil.notNull(item.getName(),"修改模块名称不允许为空");
                AssertUtil.notNull(item.getId(),"修改模块ID不允许为空");
                AssertUtil.isTrue(item.getName().matches(Constants.REGEXP_FIRST_LAST_NOT_SPACE),"修改模块名称不正确");
                existDto = projectModuleMapper.selectByProjectIdAndName(batch.getProjectId(), item.getName(), item.getId());
                if(existDto != null) {
                    throw new GenericException(ProjectModuleError.PROJECT_NAME_EXIST_ERROR);
                }
                BeanUtils.copyProperties(item, dto);
                dto.setUpdateUserId(userId);
                dto.setTimeUpdate(now);
                count += projectModuleMapper.update(dto);
            }
        }

        if(!CollectionUtils.isEmpty(batch.getInsert())){
            // 判断输入项目名称是否重复
            Set<String> names = batch.getInsert().stream().map(ProjectModuleDTO2::getName).collect(Collectors.toSet());
            if(names.size() != batch.getInsert().size()) {
                throw new CustomException(ResultCode.PARAM_DUPLICATION);
            }
            for (ProjectModuleDTO2 item : batch.getInsert()){
                AssertUtil.notNull(item.getName(),"新增模模块名称不允许为空");
                AssertUtil.isTrue(item.getName().matches(Constants.REGEXP_FIRST_LAST_NOT_SPACE),"修改模块名称不正确");
                existDto = projectModuleMapper.selectByProjectIdAndName(batch.getProjectId(), item.getName(), null);
                if(existDto != null) throw new GenericException(ProjectModuleError.PROJECT_NAME_EXIST_ERROR);
                BeanUtils.copyProperties(item,dto);
                dto.setId(null);
                dto.setProjectId(batch.getProjectId());
                dto.setCreateUserId(userId);
                dto.setUpdateUserId(userId);
                dto.setTimeCreate(now);
                dto.setTimeUpdate(now);
                dto.setStatus(1);
                count += projectModuleMapper.insert(dto);
            }
        }
        return ResponseResult.defaultSuccess(count);
    }

    @Override
    public ResponseResult selectListScripts(ProjectModuleSearch search) {
        AssertUtil.notNull(search,"参数异常");

        PageDataResult pageDataResult = new PageDataResult();

        if (null == search.getPageNum() || search.getPageNum().intValue() == 0) {
            search.setPageNum(1);
        }
        if (null == search.getPageSize() || search.getPageSize().intValue() == 0) {
            search.setPageSize(10);
        }

        if(search.getPageNum().intValue() < 0 || search.getPageSize().intValue() < 0) {
            pageDataResult.setTotals(0);
            pageDataResult.setList(Lists.newArrayList());
            return ResponseResult.defaultSuccess(pageDataResult);
        }
        PageHelper.startPage(search.getPageNum(), search.getPageSize());
        List<ProjectModuleScriptsDTO> list = projectModuleMapper.selectListScripts(search);

        PageInfo<ProjectModuleScriptsDTO> pageInfo = new PageInfo<>(list);
        pageDataResult.setTotals((int) pageInfo.getTotal());
        pageDataResult.setList(list);

        return ResponseResult.defaultSuccess(pageDataResult);
    }

    @Override
    @Transactional
    public ResponseResult batchCommon(ProjectModuleCommonBatchDTO batch) {
        AssertUtil.notNull(batch,"参数异常");

        User currUser = (User) SecurityUtils.getSubject().getPrincipal();
        if(currUser == null)throw new CustomException(ResultCode.PERMISSION_EXPIRE);
        Integer userId = currUser.getId();
        LocalDateTime now = LocalDateTime.now();

        List<ProjectModuleDTO2> existDto;
        int count = 0;

        redisService.remove(REDIS_KEY_ALL_MODULE_COMMON);
        // 1. 先删除，再修改，最后新增  防止名称重复
        // 1 物理删除
        if(batch.getDelete() != null && !CollectionUtils.isEmpty(batch.getDelete()))
            count += this.projectModuleMapper.deleteCommon(batch.getDelete());

        ProjectModuleDTO dto = new ProjectModuleDTO();
        if(batch.getUpdate() != null && !CollectionUtils.isEmpty(batch.getUpdate())){
            for (ProjectModuleDTO2 item : batch.getUpdate()){
                AssertUtil.notNull(item.getId(),"修改模块ID不允许为空");
                AssertUtil.notNull(item.getName(),"修改模块名称不允许为空");
                existDto = projectModuleMapper.selectCommonByName(item.getName(), item.getId());
                if(!CollectionUtils.isEmpty(existDto)) throw new GenericException(ProjectModuleError.PROJECT_NAME_EXIST_ERROR);
                BeanUtils.copyProperties(item,dto);
                dto.setUpdateUserId(userId);
                dto.setTimeUpdate(now);
                count += projectModuleMapper.updateCommon(dto);
            }
        }

        if(batch.getInsert() != null && !CollectionUtils.isEmpty(batch.getInsert())){
            for (ProjectModuleDTO2 item : batch.getInsert()){
                AssertUtil.notNull(item.getName(),"新增模模块名称不允许为空");
                existDto = projectModuleMapper.selectCommonByName(item.getName(), null);
                if(!CollectionUtils.isEmpty(existDto)) throw new GenericException(ProjectModuleError.PROJECT_NAME_EXIST_ERROR);
                BeanUtils.copyProperties(item,dto);
                dto.setCreateUserId(userId);
                dto.setUpdateUserId(userId);
                dto.setTimeCreate(now);
                dto.setTimeUpdate(now);
                count += projectModuleMapper.insertCommon(dto);
            }
        }
        redisService.remove(REDIS_KEY_ALL_MODULE_COMMON);
        return ResponseResult.defaultSuccess(count);
    }

    @Override
    public ResponseResult selectCommon() {

        String cacheData = redisService.get(REDIS_KEY_ALL_MODULE_COMMON);
        if(!StringUtils.isEmpty(cacheData)){
            try {
                return ResponseResult.defaultSuccess(JSON.parseObject(cacheData, new TypeReference<List<ProjectModuleDTO2>>() {
                }));
            }catch (Exception e){
                log.info(e.getMessage());
            }
        }

        List<ProjectModuleDTO2> list = projectModuleMapper.selectCommonByName(null, null);
        if(!CollectionUtils.isEmpty(list)) {
            redisService.setex(REDIS_KEY_ALL_MODULE_COMMON, JSON.toJSONString(list)
                    , TimeUnit.SECONDS, redisService.getExpire(REDIS_CACHE_EXPIRE, 60));
        }

        return ResponseResult.defaultSuccess(list);
    }

    @Override
    public int delete(List<Integer> ids) {
        return projectModuleMapper.delete(ids, null, null);
    }

}
